//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "SearchPrositePattern.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <iostream>
#include <fstream>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTHTEXT 1000
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SearchPrositePattern::SearchPrositePattern () {
  
  this->sequence        = new String ();
  this->pattern         = new String ();
  
  this->extendedPattern = new TListE <String> ();
  this->segments        = new TListE <String> ();
  this->positions       = new TListE <int> ();
  
  this->toString        = new String ();
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SearchPrositePattern::SearchPrositePattern (const SearchPrositePattern& searchPrositePattern) {
  
  this->sequence         = new String (searchPrositePattern.sequence);
  this->pattern          = new String (searchPrositePattern.pattern);
  
  this->extendedPattern  = new TListE <String> (searchPrositePattern.extendedPattern);
  this->segments         = new TListE <String> (searchPrositePattern.segments);
  this->positions        = new TListE <int> (searchPrositePattern.positions);
  
  this->toString         = new String ();
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SearchPrositePattern::SearchPrositePattern (const SearchPrositePattern* searchPrositePattern) {
  
  this->sequence         = new String (searchPrositePattern->sequence);
  this->pattern          = new String (searchPrositePattern->pattern);
  
  this->extendedPattern  = new TListE <String> (searchPrositePattern->extendedPattern);
  this->segments         = new TListE <String> (searchPrositePattern->segments);
  this->positions        = new TListE <int> (searchPrositePattern->positions);
  
  this->toString         = new String ();
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SearchPrositePattern::~SearchPrositePattern () {
  
  if (this->sequence)        delete this->sequence;
  if (this->pattern)         delete this->pattern;
  if (this->extendedPattern) delete this->extendedPattern;
  if (this->segments)        delete this->segments;
  if (this->positions)       delete this->positions;
  if (this->toString)        delete this->toString;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SearchPrositePattern::Sequence (String* sequence) {
  
  if (sequence) this->sequence->In(sequence);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SearchPrositePattern::Pattern (String* pattern) {
  
  if (pattern) this->pattern->In(pattern);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SearchPrositePattern::ExtendedPattern (TListE <String>* extendedPattern) {
  
  if (extendedPattern) *(this->extendedPattern) = *(extendedPattern);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SearchPrositePattern::Segments (TListE <String>* segments) {
  
  if (segments) *(this->segments) = *(segments);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void SearchPrositePattern::Positions (TListE <int>* positions) {
  
  if (positions) *(this->positions) = *(positions);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* SearchPrositePattern::Sequence (void) {
  
  return this->sequence;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* SearchPrositePattern::Pattern (void) {
  
  return this->pattern;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <String>* SearchPrositePattern::ExtendedPattern (void) {
  
  return this->extendedPattern;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <String>* SearchPrositePattern::Segments (void) {
  
  return this->segments;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <int>* SearchPrositePattern::Positions (void) {
  
  return this->positions;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* SearchPrositePattern::ToString (void) {
  
  this->toString->In("\n");
  this->toString->Add("Sequence: ");
  this->toString->Add(this->sequence);
  this->toString->Add("\n");
  
  this->toString->Add("Pattern : ");
  this->toString->Add(this->pattern);
  this->toString->Add("\n");
  
  this->toString->Add("\nExtended Patterns: \n\n");

  this->extendedPattern->SetInitial();
  while (this->extendedPattern->SetNext()) {
    this->toString->Add("Pattern : ");
    this->toString->Add(this->extendedPattern->GetCurrent());
    this->toString->Add("\n");
  }
  
  this->toString->Add("\n");
  
  this->segments->SetInitial();
  this->positions->SetInitial();
  while (this->segments->SetNext() && this->positions->SetNext()) {
    
    this->toString->Add("Position: ");   
    this->toString->Add(*(this->positions->GetCurrent()));
    this->toString->Add(" - Segment: "); 
    this->toString->Add(this->segments->GetCurrent());
    this->toString->Add("\n");
    
    this->toString->Add("Sequence: "); 
    this->toString->Add(this->sequence); 
    this->toString->Add("\n");
    this->toString->Add("Pattern : ");
    for (int i = 0; i < *(this->positions->GetCurrent()); i++)
      this->toString->Add("-");
    this->toString->Add(this->segments->GetCurrent());
    for (int i = *(this->positions->GetCurrent()) + this->segments->GetCurrent()->Length(); i < this->sequence->Length(); i++)
      this->toString->Add("-");
    this->toString->Add("\n");
  }
  
  return this->toString;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SearchPrositePattern::SearchPattern (void) {
  
  if (!this->sequence || !this->sequence->Length() || !this->pattern || !this->pattern->Length())
    return false;
  
  this->segments->Clear();
  this->positions->Clear();
  
  if (!this->ExpandPattern())
    return false;
  
  this->extendedPattern->SetInitial();
  while (this->extendedPattern->SetNext())
    if (!(this->FoundPatternAndUpdateSegments(this->extendedPattern->GetCurrent())))
      return false;
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SearchPrositePattern::SearchPattern (String* sequence, String* pattern) {
  
  if (!sequence || !sequence->Length() || !pattern || !pattern->Length())
    return false;
  
  this->Sequence(sequence);
  this->Pattern(pattern);
  
  return this->SearchPattern();
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SearchPrositePattern::SearchPatternAdvance (void) {
  
  if (!this->sequence || !this->sequence->Length() || !this->pattern || !this->pattern->Length())
    return false;
  
  this->segments->Clear();
  this->positions->Clear();
  
  if (!this->ExpandPattern())
    return false;
  
  this->extendedPattern->SetInitial();
  while (this->extendedPattern->SetNext())
    if (!(this->FoundPatternAndUpdateSegments(this->extendedPattern->GetCurrent())))
      return false;
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SearchPrositePattern::SearchPatternAdvance (String* sequence, String* pattern) {
  
  if (!sequence || !sequence->Length() || !pattern || !pattern->Length())
    return false;
  
  this->Sequence(sequence);
  this->Pattern(pattern);
  
  return this->SearchPatternAdvance();
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SearchPrositePattern::ExpandPattern (void) {
  
  if (!this->extendedPattern || !this->pattern || !this->pattern->Length())
    return false;
  
  this->extendedPattern->Clear();
  
  char             tmpPattern [this->pattern->Length() + 1];
  char*            parts           = NULL;
  
  TListE <String>* expandedPattern = new TListE <String> ();
  TListE <String>* splitPattern    = new TListE <String> ();
  
  strcpy(tmpPattern, this->pattern->Out());

  parts = strtok(tmpPattern, "-[]");
  while (parts) {
    splitPattern->Add(new String (parts));    
    parts = strtok(NULL, "-[]");
  }

  for (int i = 0; i < splitPattern->Length(); i++) {
    
    if (splitPattern->Get(i)->Out()[0] == 'x') {
      
      if (splitPattern->Get(i)->Length() == 1) {
        
        for (int j = 0; j < this->extendedPattern->Length(); j++) 
          this->extendedPattern->Get(j)->Add("x-");
        
      }
      else {
        
        if (splitPattern->Get(i)->Contain(",")) {
          
          int lengthXIni = 0, lengthXEnd = 0;
          sscanf(splitPattern->Get(i)->Out(), "x(%d,%d)", &lengthXIni, &lengthXEnd);
          
          TListE <String>* tmpExtendedPattern = new TListE <String> ();
          
          for (int j = 0; j < this->extendedPattern->Length(); j++) 
            for (int k = 0; k <= (lengthXEnd - lengthXIni); k++) {
              
              tmpExtendedPattern->Add(new String(this->extendedPattern->Get(j)));
              
              for (int l = 0; l < (lengthXIni + k); l++)
                tmpExtendedPattern->GetFinal()->Add("x-");
              
            }
          
          if (this->extendedPattern) delete this->extendedPattern;
          
          this->extendedPattern = tmpExtendedPattern;
          
        }
        else {
          
          int lengthX = 0;
          sscanf(splitPattern->Get(i)->Out(), "x(%d)", &lengthX);
          
          for (int j = 0; j < this->extendedPattern->Length(); j++)
            for (int k = 0; k < lengthX; k++)
              this->extendedPattern->Get(j)->Add("x-");
          
        }
        
      }
      
    }
    else {

      if (!this->extendedPattern->Length())
        this->extendedPattern->Add(new String (""));

      for (int j = 0; j < this->extendedPattern->Length(); j++) {

        if (splitPattern->Get(i)->Length() > 1)
          this->extendedPattern->Get(j)->Add("[");

        this->extendedPattern->Get(j)->Add(splitPattern->Get(i));
        
        if (splitPattern->Get(i)->Length() > 1)
          this->extendedPattern->Get(j)->Add("]");
        
        this->extendedPattern->Get(j)->Add("-");
        
      }

    }
    
  }
  
  this->extendedPattern->SetInitial();
  while (this->extendedPattern->SetNext()) {
    char tmpPattern [this->extendedPattern->GetCurrent()->Length()];
    strncpy(tmpPattern, this->extendedPattern->GetCurrent()->Out(), this->extendedPattern->GetCurrent()->Length() - 1);
    tmpPattern[this->extendedPattern->GetCurrent()->Length() - 1] = '\0';
    this->extendedPattern->GetCurrent()->In(tmpPattern);
  }

  if (expandedPattern) delete expandedPattern;
  if (splitPattern)    delete splitPattern;

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SearchPrositePattern::FoundPatternAndUpdateSegments (String* patternIn) {
  
  if (!patternIn || !patternIn->Length() || !this->sequence || !this->sequence->Length())
    return false;
  
  char             tmpPattern [patternIn->Length() + 1];
  char*            parts           = NULL;
  
  TListE <String>* splitPattern    = new TListE <String> ();
  
  strcpy(tmpPattern, patternIn->Out());
  
  parts = strtok(tmpPattern, "-[]");
  while (parts) {
    splitPattern->Add(new String (parts));    
    parts = strtok(NULL, "-[]");
  }
  
  for (int i = 0; i < this->sequence->Length(); i++) {
    
    int  counter = 0;
    char segment [splitPattern->Length() + 1];
    
    for (int j = 0; j < splitPattern->Length(); j++) {
      
      if (splitPattern->Get(j)->Length() == 1) {
        
        if ((splitPattern->Get(j)->Out()[0] == 'x') || (splitPattern->Get(j)->Out()[0] == this->sequence->Out()[i + j])) 
          segment[counter++] = this->sequence->Out()[i + j];
        else break;
        
      }
      else {
        
        bool cond = false;
        
        for (int k = 0; k < splitPattern->Get(j)->Length(); k++)
          if (splitPattern->Get(j)->Out()[k] == this->sequence->Out()[i + j]) {
            segment[counter++] = this->sequence->Out()[i + j];
            cond               = true;
            break;
          }
        
        if (!cond) break;
        
      }
      
    }
    
    if (counter == splitPattern->Length()) {
      segment[counter] = '\0';
      this->segments->Add(new String (segment));
      this->positions->Add(new int (i));
    }
    
  }  
  
  if (splitPattern) delete splitPattern;

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool SearchPrositePattern::FoundPatternAdvanceAndUpdateSegments (String* patternIn) {
  
  if (!patternIn || !patternIn->Length() || !this->sequence || !this->sequence->Length())
    return false;
  
  char             tmpPattern [patternIn->Length() + 1];
  char*            parts           = NULL;
  
  TListE <String>* splitPattern    = new TListE <String> ();
  
  strcpy(tmpPattern, patternIn->Out());
  
  parts = strtok(tmpPattern, "-[]");
  while (parts) {
    splitPattern->Add(new String (parts));    
    parts = strtok(NULL, "-[]");
  }
  
  for (int i = 0; i < this->sequence->Length(); i++) {
    
    int  counter = 0;
    char segment [splitPattern->Length() + 1];
    
    for (int j = 0; j < splitPattern->Length(); j++) {
      
      if (splitPattern->Get(j)->Length() == 1) {
        
        if ((splitPattern->Get(j)->Out()[0] == 'x') || (splitPattern->Get(j)->Out()[0] == this->sequence->Out()[i + j])) 
          segment[counter++] = this->sequence->Out()[i + j];
        else break;
        
      }
      else {
        
        bool cond = false;
        
        for (int k = 0; k < splitPattern->Get(j)->Length(); k++)
          if (splitPattern->Get(j)->Out()[k] == this->sequence->Out()[i + j]) {
            segment[counter++] = this->sequence->Out()[i + j];
            cond               = true;
            break;
          }
        
        if (!cond) break;
        
      }
      
    }
    
    if (counter == splitPattern->Length()) {
      segment[counter] = '\0';
      this->segments->Add(new String (segment));
      this->positions->Add(new int (i));
    }
    
  }  
  
  if (splitPattern) delete splitPattern;

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
SearchPrositePattern SearchPrositePattern::operator= (const SearchPrositePattern& searchPrositePattern) {
  
  this->sequence->In(searchPrositePattern.sequence);
  this->pattern->In(searchPrositePattern.pattern);
  
  *(this->extendedPattern) = *(searchPrositePattern.extendedPattern);
  *(this->segments)        = *(searchPrositePattern.segments);
  *(this->positions)       = *(searchPrositePattern.positions);
    
  return *this;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
